package com.starview.star.operators.arrays.runtime;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IArray;
import com.starview.platform.data.IExtensibleArray;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IPattern;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.platform.data.value.Array;
import com.starview.platform.data.value.NTuple;
import com.starview.star.operators.CafeEnter;

public class ArraySequenceOps
{
  public static class ArrayNil implements IFunction
  {
    public static final String name = "__array_nil";

    @CafeEnter
    public static IValue enter() throws EvaluationException
    {
      return Array.nilArray;
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter();
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      return Refresher.generalize(TypeUtils.functionType(TypeUtils.arrayType(new TypeVar())));
    }
  }

  public static class ArrayArray implements IFunction
  {
    public static final String name = "__array_array";

    @CafeEnter
    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Array.newArray(args);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar elType = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(elType, TypeUtils.arrayType(elType)));
    }
  }

  public static class ArrayCons implements IFunction
  {
    public static final String name = "__array_cons";

    @CafeEnter
    public static IArray enter(IValue el, IExtensibleArray array) throws EvaluationException
    {
      return array.consCell(el);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter(args[0], (IExtensibleArray) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar v = new TypeVar();
      IType arrayType = TypeUtils.arrayType(v);
      return Refresher.generalize(TypeUtils.functionType(v, arrayType, arrayType));
    }
  }

  public static class ArrayAppend implements IFunction
  {
    public static final String name = "__array_append";

    @CafeEnter
    public static IValue enter(IExtensibleArray array, IValue el) throws EvaluationException
    {
      return array.addCell(el);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((IExtensibleArray) args[0], args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar v = new TypeVar();
      IType arrayType = TypeUtils.arrayType(v);
      return Refresher.generalize(TypeUtils.functionType(arrayType, v, TypeUtils.arrayType(v)));
    }
  }

  public static class UnaryArray implements IFunction
  {
    public static final String name = "__unary_array";

    @CafeEnter
    public static IValue enter(IValue el) throws EvaluationException
    {
      return Array.newArray(new IValue[] { el });
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Array.newArray(args);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar elType = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(elType, TypeUtils.arrayType(elType)));
    }
  }

  public static class BinaryArray implements IFunction
  {
    public static final String name = "__binary_array";

    @CafeEnter
    public static IValue enter(IValue el1, IValue el2) throws EvaluationException
    {
      return Array.newArray(new IValue[] { el1, el2 });
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Array.newArray(args);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar elType = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(elType, elType, TypeUtils.arrayType(elType)));
    }
  }

  public static class TernaryArray implements IFunction
  {
    public static final String name = "__ternary_array";

    @CafeEnter
    public static IValue enter(IValue el1, IValue el2, IValue el3) throws EvaluationException
    {
      return Array.newArray(new IValue[] { el1, el2, el3 });
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Array.newArray(args);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar elType = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(elType, elType, elType, TypeUtils.arrayType(elType)));
    }
  }

  public static class ArrayEmptyMatch implements IPattern
  {
    public static final String name = "__array_empty_match";

    @CafeEnter
    public static IValue matches(IValue list) throws EvaluationException
    {
      IArray array = (IArray) list;
      if (array.isEmpty()) {
        return NTuple.$0Enum;
      } else
        return null;
    }

    @Override
    public IValue match(IValue list) throws EvaluationException
    {
      return matches(list);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      return Refresher.generalize(TypeUtils.patternType(TypeUtils.tupleType(), TypeUtils.arrayType(new TypeVar())));
    }
  }

  public static class ArrayHeadMatch implements IPattern
  {
    public static final String name = "__array_head_match";

    @CafeEnter
    public static IValue matches(IValue list) throws EvaluationException
    {
      Array array = (Array) list;

      if (array.size() >= 1)
        return NTuple.tuple(array.getCell(0), array.slice(1));
      else
        return null;
    }

    @Override
    public IValue match(IValue list) throws EvaluationException
    {
      return matches(list);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar e = new TypeVar();
      IType l = TypeUtils.arrayType(e);

      return Refresher.generalize(TypeUtils.patternType(TypeUtils.tupleType(e, l), l));
    }
  }

  public static class ArrayTailMatch implements IPattern
  {
    public static final String name = "__array_tail_match";

    @CafeEnter
    public static IValue matches(IValue list) throws EvaluationException
    {
      Array array = (Array) list;

      int size = array.size();

      if (size >= 1)
        return NTuple.tuple(array.slice(0, size - 1), array.getCell(size - 1));
      else
        return null;
    }

    @Override
    public IValue match(IValue list) throws EvaluationException
    {
      return matches(list);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar e = new TypeVar();
      IType l = TypeUtils.arrayType(e);

      return Refresher.generalize(TypeUtils.patternType(TypeUtils.tupleType(l, e), l));
    }
  }
}
